#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
#include <sys/time.h>
 
#include "data_type.h"
#include "cube.h"
#include "cube_define.h"
#include "cube_record.h"

#include "user_define.h"
#include "action_define.h"
#include "tcm_constants.h"
#include "tcm_structures.h"
#include "tcm_key_manage.h"
#include "tcm_key_desc.h"
#include "tcm_pik_desc.h"
#include "tcmfunc.h"
#include "key_manage.h"

// add para lib_include
int key_manage_init(void * sub_proc, void * para)
{
	int ret;
	// add yorself's module init func here
	return 0;
}
int key_manage_start(void * sub_proc, void * para)
{
	int ret;
	void * recv_msg;
	int type;
	int subtype;
	// add yorself's module exec func here
	while(1)
	{
		usleep(time_val.tv_usec);
		ret=ex_module_recvmsg(sub_proc,&recv_msg);
		if(ret<0)
			continue;
		if(recv_msg==NULL)
			continue;
		type=message_get_type(recv_msg);
		subtype=message_get_subtype(recv_msg);
		if(!memdb_find_recordtype(type,subtype))
		{
			printf("message format (%d %d) is not registered!\n",
			message_get_type(recv_msg),message_get_subtype(recv_msg));
			continue;
		}
		if((type==TYPE(USER_DEFINE))&&(subtype==SUBTYPE(USER_DEFINE,RETURN)))
		{
			ret=proc_keymanage_return(sub_proc,recv_msg);
		}
		else if((type==TYPE(GENERAL_RETURN))&&(subtype==SUBTYPE(GENERAL_RETURN,STRING)))
		{
            ret = proc_general_process(sub_proc,recv_msg);
		}
        else
	        ret=ex_module_sendmsg(sub_proc,recv_msg);
	}
	return 0;
}

int proc_general_process(void * sub_proc,void *recv_msg)
{
    RECORD(GENERAL_RETURN,STRING) * action_info;
    int ret;

	ret=message_get_record(recv_msg,&action_info,0);
	if(ret<0)
		return ret;
    printf("enter proc_general process!\n");

    if(Strcmp(action_info->name,"key_exchange")==0)
    {
		 ret=proc_remotekey_send(sub_proc,recv_msg);
    }   
    else if(Strcmp(action_info->name,"pcr_quote")==0)
    {
		 ret=proc_action_process(sub_proc,recv_msg);
    }
    return ret;
          
}
	
int proc_keymanage_return(void * sub_proc,void * recv_msg)
{
	int ret;
	RECORD(USER_DEFINE,RETURN) * login_return;
	RECORD(MESSAGE,INSTANCE_INFO) * instance_info;
	char user_name[DIGEST_SIZE];
	void * new_msg;
    MSG_EXPAND * msg_expand;
	
	BYTE local_uuid[DIGEST_SIZE];	
	char proc_name[DIGEST_SIZE];	

    print_cubeaudit("enter keymanage_return function!");

	ret=message_get_record(recv_msg,&login_return,0);
	if(ret<0)
		return ret;

    if(login_return->return_code!=SUCCEED)
        return -EINVAL;

	ret = message_remove_expand(recv_msg,TYPE_PAIR(MESSAGE,INSTANCE_INFO),&msg_expand);
	if(ret<0)
		return ret;
	if(msg_expand==NULL)
		return -ENOMEM;
    instance_info=msg_expand->expand;
    if(instance_info==NULL)
        return -EINVAL;
	
    proc_share_data_setvalue("user_name",instance_info->user_name);

    print_cubeaudit("user name is %s!",instance_info->user_name);
	//proc_share_data_getvalue("proc_name",instance_info->proc_name);
	//proc_share_data_getvalue("uuid",instance_info->node_uuid);

	new_msg=message_create(TYPE_PAIR(MESSAGE,INSTANCE_INFO),recv_msg);	
	if(new_msg==NULL)
		return -EINVAL;
	ret=message_add_record(new_msg,instance_info);
	if(ret<0)
		return ret;
	
	ret=ex_module_sendmsg(sub_proc,new_msg);
	return ret;
}

int proc_remotekey_send(void * sub_proc,void * recv_msg)
{
	int ret;
	RECORD(GENERAL_RETURN,STRING) * login_sendkey;
	RECORD(MESSAGE,INSTANCE_INFO) * instance_info;
	char user_name[DIGEST_SIZE];
	void * new_msg;
	
	BYTE local_uuid[DIGEST_SIZE];	
	char proc_name[DIGEST_SIZE];	

	ret=message_get_record(recv_msg,&login_sendkey,0);
	if(ret<0)
		return ret;

	instance_info=Talloc0(sizeof(*instance_info));
	if(instance_info==NULL)
		return -ENOMEM;
	
	proc_share_data_getvalue("proc_name",instance_info->proc_name);
	Strncpy(instance_info->user_name,login_sendkey->return_value,DIGEST_SIZE);
	proc_share_data_getvalue("uuid",instance_info->node_uuid);

	new_msg=message_create(TYPE_PAIR(MESSAGE,INSTANCE_INFO),recv_msg);	
//	ret=message_add_expand_data(recv_msg,TYPE_PAIR(MESSAGE,INSTANCE_INFO),instance_info);	
//	if(ret<0)
//		return ret;
	ret=message_add_record(new_msg,instance_info);
	if(ret<0)
		return ret;	
	ret=ex_module_sendmsg(sub_proc,new_msg);
	return ret;
}

int proc_action_process(void * sub_proc,void * recv_msg)
{
	int ret;
	RECORD(ACTION_DEFINE,HANDSHAKE) * action_info;
	RECORD(GENERAL_RETURN,STRING) * getkey_info;
	RECORD(MESSAGE,INSTANCE_INFO) * instance_info;
	char user_name[DIGEST_SIZE];
	void * new_msg;
	
	BYTE local_uuid[DIGEST_SIZE];	
	char proc_name[DIGEST_SIZE];	
    MSG_EXPAND * msg_expand;

    printf("enter proc_action_process!\n");

	ret=message_get_define_expand(recv_msg,&msg_expand,TYPE_PAIR(ACTION_DEFINE,HANDSHAKE));
	if(ret<0)
		return ret;
    if(msg_expand==NULL)
        return -EINVAL;
    action_info=msg_expand->expand;
    if(action_info==NULL)
        return -EINVAL;

    if(action_info->handshake_type==PCR_QUOTE)
    {
        if(action_info->step==1)
            return proc_action_quote_req(sub_proc,recv_msg);
        else if(action_info->step==2)
            return proc_action_quote_report(sub_proc,recv_msg);
    }

    return -EINVAL;

}
int proc_action_quote_req(void * sub_proc,void * recv_msg)
{
	int ret;
	RECORD(ACTION_DEFINE,HANDSHAKE) * action_info;
	RECORD(GENERAL_RETURN,INT) * pcr_info;
	RECORD(MESSAGE,INSTANCE_INFO) * instance_info;
	char user_name[DIGEST_SIZE];
	void * new_msg;
    RECORD(TCM_PIK_DESC,PCRQUOTE) * pcrquote;
    MSG_EXPAND * msg_expand;

    printf("enter proc_action_quote_req!\n");
    // get pcr_info and generate quote req data
    ret = message_remove_expand(recv_msg,TYPE_PAIR(GENERAL_RETURN,INT),&msg_expand);
    if(msg_expand==NULL)
        return -EINVAL;
    if(msg_expand->expand==NULL)
        return -EINVAL;
    pcr_info=msg_expand->expand;

    pcrquote=Talloc0(sizeof(*pcrquote));
    if(pcrquote==NULL)
        return -ENOMEM;
    printf("prepare to init pcrquote!\n");
    TCM_ExInitPcrComposite(&pcrquote->pcrComp);
    TCM_ExAddPcrComposite(&pcrquote->pcrComp,pcr_info->return_value,NULL);
    
    printf("init pcrquote succeed!\n");
    // get shakehand info 
	ret=message_get_define_expand(recv_msg,&msg_expand,TYPE_PAIR(ACTION_DEFINE,HANDSHAKE));
	if(ret<0)
		return ret;
    if(msg_expand==NULL)
    {
        return -EINVAL;        
    }
    printf("get handshake info!\n");
    action_info=msg_expand->expand;
    // user shakehand info to file the QUOTE req 

    Memcpy(pcrquote->nonce,action_info->nonce,DIGEST_SIZE);
    Strncpy(pcrquote->userinfo.username,action_info->server,DIGEST_SIZE);


    ret = message_add_expand_data(recv_msg,TYPE_PAIR(TCM_PIK_DESC,PCRQUOTE),pcrquote);
	if(ret<0)
		return ret;	
	ret=ex_module_sendmsg(sub_proc,recv_msg);
	return ret;
}

int proc_action_quote_report(void * sub_proc,void * recv_msg)
{
	int ret;
	RECORD(ACTION_DEFINE,HANDSHAKE) * action_info;
	RECORD(GENERAL_RETURN,INT) * pcr_info;
	RECORD(MESSAGE,INSTANCE_INFO) * instance_info;
	char user_name[DIGEST_SIZE];
	void * new_msg;
    RECORD(TCM_PIK_DESC,PCRQUOTE) * pcrquote;
    MSG_EXPAND * msg_expand;
    BYTE local_uuid[DIGEST_SIZE];
         

    printf("enter proc_action_quote_report!\n");
    // get shakehand info 
	ret=message_get_define_expand(recv_msg,&msg_expand,TYPE_PAIR(ACTION_DEFINE,HANDSHAKE));
	if(ret<0)
		return ret;
    if(msg_expand==NULL)
    {
        return -EINVAL;        
    }
    printf("get handshake info!\n");
    action_info=msg_expand->expand;
    // user shakehand info to file the QUOTE req 
    // get pcrreq info 
	ret=message_remove_expand(recv_msg,TYPE_PAIR(TCM_PIK_DESC,PCRQUOTE),&msg_expand);
	if(ret<0)
		return ret;
    printf("get pcrquote!\n");
    if(msg_expand==NULL)
    {
        return -EINVAL;        
    }
    pcrquote=msg_expand->expand;
    printf("get pcrquote %p!\n",pcrquote);

    proc_share_data_getvalue("uuid",pcrquote->userinfo.node_uuid);

    //Memcpy(pcrquote->userinfo.expand_digest,action_info->nonce,DIGEST_SIZE);
    ret = message_add_expand_data(recv_msg,TYPE_PAIR(TCM_PIK_DESC,PCRQUOTE),pcrquote);
	if(ret<0)
		return ret;	
    printf("get pcrquote info!\n");
	ret=ex_module_sendmsg(sub_proc,recv_msg);
	return ret;
}
